> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# useGoogleDriveBackupReadiness

<Card title="Recommended: JavaScript SDK with React Hooks" icon="react" color="#4779FE">
  For new React apps, we recommend the JavaScript SDK with React Hooks (`@dynamic-labs-sdk/react-hooks`) instead of the legacy React SDK documented here. The JS SDK comes with many benefits such as a much smaller bundle size and other optimizations. Use the [React quickstart (JavaScript SDK)](/javascript/reference/react-quickstart) to get started.
</Card>

### Summary

The `useGoogleDriveBackupReadiness` hook is a pre-flight check that tells you whether the user's linked Google account has the OAuth scopes required to back up MPC key shares to Google Drive. Use it to detect — and recover from — missing-scope situations *before* triggering an MPC reshare ceremony, so you don't burn a ceremony on an upload that will fail.

It pairs with [`useWalletBackup`](/react/reference/hooks/embedded-wallets/usewalletbackup) as the first layer of a two-layer defense: pre-flight readiness (this hook) catches the common cases; post-flight error inspection (via `try/catch` around `backupWallet` and `isInsufficientGoogleDriveScopesError`) handles legacy tokens captured before scope tracking was introduced.

For more information on wallet backup, see the [Google Drive backup documentation](/react/wallets/embedded-wallets/mpc/google-drive-backup).

The hook needs to be initialized within a child of [DynamicContextProvider](/react/reference/providers/dynamiccontextprovider).

### Functions

#### `check`

Reads the user's stored Google OAuth token and compares its granted scopes against the scopes required for Google Drive backup.

<Note>This method is headless.</Note>

**Returns:** `Promise<GoogleDriveBackupReadiness>` — resolves with the new readiness state. The same object is also written to the hook's state (so any of `status`, `missingScopes`, `accessToken`, `error` returned from the hook will reflect the latest result on the next render).

**Example:**

```typescript theme={"system"}
const { check } = useGoogleDriveBackupReadiness();

const result = await check();
if (result.status === 'ready') {
  // Safe to call backupWallet(...)
}
```

#### `requestAccess`

Re-prompts the Google consent popup so the user can grant the missing scopes (or link a Google account if none is linked yet), refreshes the user, and re-runs `check()` against the new token. Use this after `check()` returns `status: 'needs-access'`.

<Note>This method opens a popup and uses Dynamic's social linking flow.</Note>

**Returns:** `Promise<GoogleDriveBackupReadiness>` — resolves with the readiness state *after* the consent popup completes. Inspect `status` to see whether access was successfully granted.

**Example:**

```typescript theme={"system"}
const { requestAccess } = useGoogleDriveBackupReadiness();

const result = await requestAccess();
if (result.status === 'ready') {
  // User granted the scopes; safe to call backupWallet(...)
} else if (result.status === 'needs-access') {
  // User cancelled or didn't grant the required scopes
}
```

#### `reset`

Clears the hook back to its initial `'idle'` state. Useful when the user navigates away from the backup CTA and you want to discard cached readiness state.

**Returns:** `void`

### Properties

#### `status`

The current readiness status.

**Type:** `'idle' | 'ready' | 'needs-access' | 'error'`

| Status           | Meaning                                                                                                                         |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `'idle'`         | The hook has not been checked yet, or `reset()` was called.                                                                     |
| `'ready'`        | The stored token includes both required Google Drive scopes. Backup should succeed (barring transient errors).                  |
| `'needs-access'` | Backup is unlikely to succeed without user intervention. Covers three sub-cases — see below. Call `requestAccess()` to recover. |
| `'error'`        | The underlying token fetch or relink rejected. Inspect `error` for the cause.                                                   |

The `'needs-access'` status covers three distinct sub-cases, distinguishable by `missingScopes`:

1. **No Google account linked** — `missingScopes` is populated with the full required set (`GOOGLE_DRIVE_BACKUP_REQUIRED_SCOPES`), so you can render copy directly without checking the empty case.
2. **Some scopes missing** — `missingScopes` lists only the missing scopes.
3. **Legacy tokens (unknown scopes)** — `missingScopes` is an empty array. These are tokens captured before scope tracking shipped; `requestAccess()` forces a fresh token so the scopes get recorded.

#### `isChecking`

`true` while a `check()` or `requestAccess()` call is in flight.

**Type:** `boolean`

#### `missingScopes`

Scopes the user still needs to grant. See the table above for how to interpret this in conjunction with `status`.

**Type:** `readonly string[]`

#### `accessToken`

The user's current Google OAuth access token, if one was successfully fetched. Present in `'ready'` and most `'needs-access'` results; absent when no Google account is linked or when the fetch errored.

**Type:** `string | undefined`

#### `error`

The underlying error when `status === 'error'`. The token fetch and the relink/consent popup both surface here.

**Type:** `unknown`

### Usage

The recommended pattern is **two-layer defense**:

* **Layer 1 — pre-flight readiness:** call `check()` when the user opens the "Backup to Google Drive" CTA. If `status` is `'needs-access'`, prompt the user and call `requestAccess()` to re-prompt the Google consent screen, then proceed with `backupWallet(...)`.
* **Layer 2 — post-flight recovery:** for legacy users where the stored OAuth scopes weren't recorded, pre-flight cannot tell whether the upload will succeed. Pass `{ throwOnError: true }` to `useWalletBackup` and use `try/catch` to detect the insufficient-scopes case after the attempt — re-prompt consent and retry from the `catch` block.

```tsx theme={"system"}
import {
  useGoogleDriveBackupReadiness,
  useWalletBackup,
  isInsufficientGoogleDriveScopesError,
  CloudBackupProvider,
} from '@dynamic-labs/sdk-react-core';

function BackupButton({ wallet }) {
  const { status, missingScopes, isChecking, check, requestAccess } =
    useGoogleDriveBackupReadiness();

  // Opt into the throw-based error surface so we can catch
  // insufficient-scope failures from backupWallet.
  const { backupWallet } = useWalletBackup({ throwOnError: true });

  const onBackup = async () => {
    // Layer 1: pre-flight readiness — saves an MPC reshare ceremony when
    // we can already tell the upload will fail.
    let r = await check();
    if (r.status === 'needs-access') {
      r = await requestAccess();
      if (r.status !== 'ready') return; // user cancelled or relink failed
    }

    try {
      await backupWallet(wallet, CloudBackupProvider.GoogleDrive);
    } catch (err) {
      // Layer 2: post-flight recovery — handles legacy tokens whose
      // stored scopes were empty so pre-flight returned 'unknown'.
      if (isInsufficientGoogleDriveScopesError(err)) {
        const recovered = await requestAccess();
        if (recovered.status === 'ready') {
          await backupWallet(wallet, CloudBackupProvider.GoogleDrive);
        }
      } else {
        throw err;
      }
    }
  };

  return (
    <>
      {status === 'needs-access' && missingScopes.length > 0 && (
        <p>We need access to: {missingScopes.join(', ')}</p>
      )}
      <button onClick={onBackup} disabled={isChecking}>
        Back up to Google Drive
      </button>
    </>
  );
}
```

<Note>
  If your code still uses the legacy `lastBackupError` field on `useWalletBackup`, the same `isInsufficientGoogleDriveScopesError` type guard works against it. `lastBackupError` is deprecated — see [`useWalletBackup`](/react/reference/hooks/embedded-wallets/usewalletbackup#lastbackuperror) for the migration path.
</Note>

### Related helpers

The same module also exports a few primitives for callers who want to build their own checks:

* `GOOGLE_DRIVE_BACKUP_REQUIRED_SCOPES` — the readonly tuple of scopes required for backup.
* `findMissingGoogleDriveBackupScopes(grantedScopes)` — given a list of granted scopes, returns the subset of required scopes that are missing.
* `hasAllGoogleDriveBackupScopes(grantedScopes)` — convenience boolean.
* `isInsufficientGoogleDriveScopesError(error)` — type guard for Google Drive backup failures caused by missing/insufficient OAuth scopes.

### Learn More

* [useWalletBackup](/react/reference/hooks/embedded-wallets/usewalletbackup)
* [Google Drive Backup Documentation](/react/wallets/embedded-wallets/mpc/google-drive-backup)
* [Social Linking](/react/users/social-linking)

### Return Value

The hook returns an object with the following properties:

```typescript theme={"system"}
{
  status: 'idle' | 'ready' | 'needs-access' | 'error';
  isChecking: boolean;
  missingScopes: readonly string[];
  accessToken?: string;
  error?: unknown;
  check: () => Promise<GoogleDriveBackupReadiness>;
  requestAccess: () => Promise<GoogleDriveBackupReadiness>;
  reset: () => void;
}
```

### Types

```typescript theme={"system"}
type GoogleDriveBackupReadinessStatus =
  | 'idle'
  | 'ready'
  | 'needs-access'
  | 'error';

type GoogleDriveBackupReadiness = {
  status: GoogleDriveBackupReadinessStatus;
  isChecking: boolean;
  missingScopes: readonly string[];
  accessToken?: string;
  error?: unknown;
};

type UseGoogleDriveBackupReadinessReturn = GoogleDriveBackupReadiness & {
  check: () => Promise<GoogleDriveBackupReadiness>;
  requestAccess: () => Promise<GoogleDriveBackupReadiness>;
  reset: () => void;
};
```
