---
title: "Google Calendar"
canonical_url: "https://docs.getdx.com/connectors/google-calendar/"
md_url: "https://docs.getdx.com/connectors/google-calendar.md"
last_updated: "2026-06-08"
---

# Google Calendar
By integrating Google Calendar with DX, you can measure time spent in meetings to analyze and improve developer focus time.

- DX imports historical events from Google Calendar, only for DX contributors.
- When a Google calendar is private (i.e., marked as not available to be viewed by other workspace members), DX will not import its events.
- Titles of the events are not imported by default, but can be enabled by contacting the DX account manager.
- When a Google calendar is set to only show free/busy but not event details, DX will import the events with "free" or "busy" titles.

To ensure accuracy in what is categorized as a meeting, DX excludes events with duration of less than 15 minutes or more than 4 hours, as well as events with only a single attendee.

## Prerequisites

To connect Google Calendar to DX, you need:

- a Google Cloud service account
- Domain Wide Delegation enabled

## Setup instructions

Follow the steps below to connect Google calendar to DX.

#### Step 1- Enable API

Enable the Google Calendar API using the following steps:

1. Go to the [API Console](https://console.developers.google.com/).
2. From the projects list, select a project or create a new one.
3. If the APIs & services page isn't already open, open the console left side menu and select **APIs & services > Library**.
4. Click on **Google Calendar API**, using the search function if needed.
5. Click **ENABLE**.

For more information, see [Enable and disable APIs](https://support.google.com/googleapi/answer/6158841?hl=en).

#### Step 2- Create service account

In this step, you'll set up a service account to make authorized API calls through domain-wide delegation.

To set up a service account, follow these steps:

1. In the Google Cloud console, go to the [Create service account](https://console.cloud.google.com/projectselector/iam-admin/serviceaccounts/create?walkthrough_id=iam--create-service-account#step_index=1) and select or create a Google Cloud project.
2. Enter a service account name to display in the Google Cloud console, and edit the service account ID if desired (you cannot change it later).
3. Optional: Enter a description of the service account.
4. If you don't want to set access controls now, click **Done** to finish creating the service account. To set access controls now, click **Create and continue**.
5. Optional: Choose one or more [IAM roles](https://cloud.google.com/iam/docs/understanding-roles) to grant to the service account on the project.
6. When you are done adding roles, click **Continue**.
7. Optional: In the **Service account users role** field, add members that need to [attach the service account to other resources](https://cloud.google.com/iam/docs/attach-service-accounts).
8. Optional: In the **Service account admins role** field, add members that need to manage the service account.
9. Click **Done** to finish creating the service account.
10. The **Unique ID** of the service account is the **Client ID** that needs to be entered when enabling Domain-wide delegation in the next step.
    ![](https://docs.getdx.com/assets/images/connectors/google-calendar/unique-id.png){class="max-w-lg mx-auto"}
11. Create a private key by browsing to **Keys > Add key**, selecting **JSON**, then clicking **Create**.
    ![](https://docs.getdx.com/assets/images/connectors/google-calendar/private-key.png){class="max-w-lg mx-auto"}
12. Download the JSON file and copy the private key (example below) which you will enter into DX.
    ```
    -----BEGIN PRIVATE KEY-----
    MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBK...
    (rest of base64-encoded data)
    -----END PRIVATE KEY-----
    ```

For more information, see [Create service accounts](https://cloud.google.com/iam/docs/service-accounts-create).

#### Step 3- Enable domain-wide delegation

Domain-wide delegation lets you grant client applications permission to access your Workspace user data without requiring consent.

1. Sign in to the [Google Admin Console](https://admin.google.com/) as a super administrator.
   - If you aren’t using a super administrator account, you can’t complete these steps.
2. Browse to [Security > Access and data control > API controls > Manage Domain Wide Delegation](https://admin.google.com/ac/owl/domainwidedelegation).
3. Click **Add new**.
4. Enter the **Client ID** for either the service account or the OAuth2 client.
5. In **OAuth Scopes**, add both of the following then click **Authorize**:
   - https://www.googleapis.com/auth/calendar.readonly
   - https://www.googleapis.com/auth/calendar.acls.readonly
6. If you get an error, the client ID might not be registered with Google or there might be duplicate or unsupported scopes.
   - If [Multi-party Approval](https://support.google.com/a/answer/13790448) is enabled for your organization, authorizing domain-wide delegation for a client app requires approval from another super admin.
7. Point to the new client ID, click **View details** and make sure that every scope is listed.
   - If a scope is not listed, click **Edit** and enter the missing scope.

For more information, see [Control API access with domain-wide delegation](https://support.google.com/a/answer/162106?product_name=UnuFlow&hl=en&visit_id=638771829504205227-789710157&rd=1&src=supportwidget0&hl=en).

#### Step 4- Finish setup

- Navigate to the connections page in DX and select "+ Connection" in the top right.
- Enter the credentials you have generated in the previous steps—refer to the information below for errors and troubleshooting.

## API reference

The table below lists the specific API endpoints that are used by DX.


| Endpoint | Documentation |
|----------------------------------------------------|---------------|
| /calendar/v3/calendars/calendarId/events | [Link](https://developers.google.com/calendar/api/v3/reference/events/list) |


## Curl commands

#### When connection verification fails

When DX verifies a Google Calendar connection, it checks if it can access calendar events using the service account and domain-wide delegation. If your connection is failing, you can test these endpoints directly using the curl commands below to troubleshoot the issue.

#### Step 1: Generate OAuth2 Token

First, generate an OAuth2 token using your service account credentials:

```bash
SERVICE_ACCOUNT_EMAIL="your-service-account@your-project.iam.gserviceaccount.com"
PRIVATE_KEY_FILE="PRIVATE_KEY_FILE"
SCOPES="https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/calendar.acls.readonly"

b64url(){ base64 | tr -d '\n=' | tr '+/' '-_'; }

HEADER=$(printf '{"alg":"RS256","typ":"JWT"}' | b64url)
NOW=$(date +%s); EXPIRY=$((NOW + 3600))
PAYLOAD=$(printf '{"iss":"%s","scope":"%s","aud":"https://oauth2.googleapis.com/token","iat":%s,"exp":%s}' \
  "$SERVICE_ACCOUNT_EMAIL" "$SCOPES" "$NOW" "$EXPIRY" | b64url)

tmp=$(mktemp)
tr -d '\r' < "$PRIVATE_KEY_FILE" > "$tmp"
SIGNATURE=$(printf '%s' "$HEADER.$PAYLOAD" | openssl dgst -sha256 -sign "$tmp" -binary | b64url)
rm -f "$tmp"

JWT="$HEADER.$PAYLOAD.$SIGNATURE"
RESPONSE=$(curl -s -X POST https://oauth2.googleapis.com/token \
  -d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=$JWT")
ACCESS_TOKEN=$(printf '%s' "$RESPONSE" | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p')
echo "$ACCESS_TOKEN"
```

#### Step 2: Test Endpoints

Replace YOUR_ACCESS_TOKEN and USER_EMAIL with your actual values before running these commands.

<h4>1. Test Calendar Events Access</h4>
<p>Once you have an access token, test calendar events access:</p>
<div class="code-block-wrapper">
  <button class="copy-button" title="Copy to clipboard">
    <svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
    <svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>
  </button>
  <pre><code class="language-bash">curl -X GET 'https://www.googleapis.com/calendar/v3/calendars/USER_EMAIL/events?maxResults=1' -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' -H 'Accept: application/json'</code></pre>
</div>

<h4>2. Test Calendar ACLs Access</h4>
<p>Test access to calendar ACL information:</p>
<div class="code-block-wrapper">
  <button class="copy-button" title="Copy to clipboard">
    <svg class="copy-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
    <svg class="check-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>
  </button>
  <pre><code class="language-bash">curl -X GET 'https://www.googleapis.com/calendar/v3/calendars/USER_EMAIL/acl' -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' -H 'Accept: application/json'</code></pre>
</div>

The response should include calendar events or ACL information with the required permissions (`calendar.readonly` and `calendar.acls.readonly`). If you receive a 401 Unauthorized error, your OAuth2 token may be invalid or expired. If you receive a 403 Forbidden error, your service account may not have domain-wide delegation enabled or the required scopes.

## Errors

The table below lists potential error codes when adding a connection in DX.


| Error | Description |
|----------------------|------------------------------------------------------------------------------------------------------------------|
| `invalid_credentials` | Your API credentials entered are not valid. |
| `invalid_permissions` | Your API token does not have the permissions required by DX. |
| `invalid_pem` | The private PEM key you entered is formatted incorrectly. |
---

## Sitemap

[Overview of all docs pages](/llms.txt)
